#include "wl_queue.h"
#include "bsp_config.h"
#include "module_config.h"
#include "FreeRTOS.h"
#include "bsp.h"
#if 0
// #define COMMINTERFACE_DEBUG_ENABLE
#ifdef COMMINTERFACE_DEBUG_ENABLE
    #define COMMINTERFACE_DEBUG(...)    LOG_TS(AM_LOG_LEVEL_WARNING, "COMMINTERFACE", __VA_ARGS__);
#else
    #define COMMINTERFACE_DEBUG(...)
#endif
#define COMMINTERFACE_INFO(...)     LOG_TS(AM_LOG_LEVEL_INFO, "COMMINTERFACE", __VA_ARGS__);

static uint8_t commDmaBuf[BUF_UART_DMA_SIZE] __attribute__((section("DMA_BUF_RAM")));
static uint8_t rxUnpackBuf[BUF_COMM_RX_UNPACK_SIZE];
static uint8_t ringBuf[BUF_COMM_RINGBUF_SIZE];


/* hardware comm <---> user id(see commUser.h) */
static const commUserIdTableTypedef commUserIdTable[] = 
{
    {ID_AT,     DEBUG_COMM_TYPE}
#if defined (MODULE_INCLUDE_ACU)
    {ID_PDA,    ACU_COMM_TYPE},
    {ID_MR813, ACU_COMM_TYPE},
#endif
#if defined (MODULE_INCLUDE_MOTOR)
    {ID_VCU1,  VCU1_COMM_TYPE},
    {ID_VCU2,  VCU2_COMM_TYPE},
    {ID_VCU1,   VCU1_COMM_TYPE},
    {ID_VCU2,   VCU2_COMM_TYPE},
#endif
#if defined (MODULE_INCLUDE_SUBG)
    {ID_CGS,    SI4463_COMM_TYPE},
#endif

#ifdef TCU_MODULE
    {ID_TCU,   TCU_COMM_TYPE},
#endif
};

static int32_t commQueueSend(uint32_t Qid, uint16_t MsgId)
{
    if (pdTRUE == xPortIsInsideInterrupt())
    {
        return wl_queue_send_isr(Qid, MsgId, 0, 0);
    }

    return wl_queue_send(Qid, MsgId, 0, 0, 3);
}

COMM_TYPE_ENUM commGetCommTypeByUserId(uint8_t id)
{
    for (uint8_t i=0; i<=sizeof(commUserIdTable)/sizeof(commUserIdTable[0]); i++)
    {
        if (id == commUserIdTable[i].userId)
        {
            return commUserIdTable[i].commType;
        }
    }

    return COMM_MAX;
}


/* comm data struct */
commDataTypedef commEntity[COMM_MAX] = 
{
#ifdef UART1_USING
    {   /* COMM_UART1 */
        .comm = &huart1,

        .rx.msgId = WL_MSG_COMM_RX_UART1_DATA,
        .rx.dmaBufSize = BUF_UART1_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART1_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART1_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART1_DATA,
        .tx.dmaBufSize = BUF_UART1_TX_ITEM_SIZE,

        .tx.ringItemSize = BUF_UART1_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART1_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART1_TX_RING_DIV,
    },
#endif

#ifdef UART2_USING
    {   /* COMM_UART2 */
        .comm = &huart2,

        .rx.msgId = WL_MSG_COMM_RX_UART2_DATA,
        .rx.dmaBufSize = BUF_UART2_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART2_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART2_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART2_DATA,
        .tx.dmaBufSize = BUF_UART2_TX_ITEM_SIZE,

        .tx.ringItemSize = BUF_UART2_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART2_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART2_TX_RING_DIV,
    },
#endif

#ifdef UART3_USING
    {   /* COMM_UART3 */
        .comm = &huart3,

        .rx.msgId = WL_MSG_COMM_RX_UART3_DATA,
        .rx.dmaBufSize = BUF_UART3_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART3_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART3_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART3_DATA,
        .tx.dmaBufSize = BUF_UART3_TX_ITEM_SIZE,


        .tx.ringItemSize = BUF_UART3_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART3_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART3_TX_RING_DIV,
    },
#endif

#ifdef UART4_USING
    {   /* COMM_UART4 */
        .comm = &huart4,

        .rx.msgId = WL_MSG_COMM_RX_UART4_DATA,
        .rx.dmaBufSize = BUF_UART4_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART4_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART4_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART4_DATA,
        .tx.dmaBufSize = BUF_UART4_TX_ITEM_SIZE,


        .tx.ringItemSize = BUF_UART4_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART4_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART4_TX_RING_DIV,
    },
#endif

#ifdef UART5_USING
    {   /* COMM_UART5 */
        .comm = &huart5,

        .rx.msgId = WL_MSG_COMM_RX_UART5_DATA,
        .rx.dmaBufSize = BUF_UART5_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART5_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART5_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART5_DATA,
        .tx.dmaBufSize = BUF_UART5_TX_ITEM_SIZE,

        .tx.ringItemSize = BUF_UART5_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART5_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART5_TX_RING_DIV,
    },
#endif

#ifdef UART6_USING
    {   /* COMM_UART6 */
        .comm = &huart6,

        .rx.msgId = WL_MSG_COMM_RX_UART6_DATA,
        .rx.dmaBufSize = BUF_UART6_RX_DMA_SIZE,

        .rx.ringItemSize = BUF_UART6_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_UART6_RX_RING_ITEM_NUM,

        .tx.msgId = WL_MSG_COMM_TX_UART6_DATA,
        .tx.dmaBufSize = BUF_UART6_TX_ITEM_SIZE,

        .tx.ringItemSize = BUF_UART6_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_UART6_TX_RING_ITEM_NUM,
        .tx.ringDiv = BUF_UART6_TX_RING_DIV,
    },
#endif
#ifdef SI4463_SPI
    {   /* COMM_SPI1 */
        .comm = &hspi3,

        .rx.msgId = WL_MSG_COMM_RX_SPI1_DATA,

        .rx.ringItemSize = BUF_SPI1_RX_ITEM_SIZE,
        .rx.ringItemNum = BUF_SPI1_RX_ITEM_NUM,
        .rx.dmaBufSize = 0,                     /* spi not use dma */

        .tx.msgId = 0,
        .tx.dmaBufSize = BUF_SPI1_TX_ITEM_SIZE,

        .tx.ringItemSize = BUF_SPI1_TX_ITEM_SIZE,
        .tx.ringItemNum = BUF_SPI1_TX_ITEM_NUM,
        .tx.ringDiv = BUF_SPI1_TX_RING_DIV,

    }
#endif
};

/* com interface init */
void commInterfaceInit(void)
{
    uint16_t dmaBufIndex = 0;
    uint16_t uppackBufIndex = 0;
    uint16_t ringBufIndex = 0;

    for (uint8_t i=0; i< sizeof(commEntity)/sizeof(commEntity[0]); i++)
    {
        commEntity[i].rx.buf = &commDmaBuf[dmaBufIndex];
        dmaBufIndex += commEntity[i].rx.dmaBufSize;

        commEntity[i].rx.ringBuf.u16ItemSize = commEntity[i].rx.ringItemSize+DMA_DATALEN_LEN;
        commEntity[i].rx.ringBuf.u16Items = commEntity[i].rx.ringItemNum;
        commEntity[i].rx.ringBuf.minLeftItem = commEntity[i].rx.ringBuf.u16Items;
        commEntity[i].rx.ringBuf.ps8Buf = &ringBuf[ringBufIndex];
        ringBufIndex += commEntity[i].rx.ringBuf.u16ItemSize*commEntity[i].rx.ringBuf.u16Items;

        commEntity[i].rx.unpack.left = 0;
        commEntity[i].rx.unpack.buf =  &rxUnpackBuf[uppackBufIndex];
        uppackBufIndex += 2*commEntity[i].rx.ringItemSize;

        commEntity[i].tx.buf = &commDmaBuf[dmaBufIndex];
        dmaBufIndex += commEntity[i].tx.dmaBufSize;

        if (commEntity[i].tx.ringDiv < 2)
        {
            commEntity[i].tx.ringDiv = 1;
        }

        for (uint8_t j=0; j<commEntity[i].tx.ringDiv; j++)
        {
            commEntity[i].tx.ringBuf[j].u16ItemSize = commEntity[i].tx.ringItemSize+DMA_DATALEN_LEN;
            commEntity[i].tx.ringBuf[j].u16Items = commEntity[i].tx.ringItemNum/commEntity[i].tx.ringDiv;
            if (j == 0)
            {
                commEntity[i].tx.ringBuf[0].u16Items += commEntity[i].tx.ringItemNum%commEntity[i].tx.ringDiv;
            }

            commEntity[i].tx.ringBuf[j].minLeftItem = commEntity[i].tx.ringBuf[j].u16Items;
            commEntity[i].tx.ringBuf[j].ps8Buf = &ringBuf[ringBufIndex];
            ringBufIndex += commEntity[i].tx.ringBuf[j].u16ItemSize*commEntity[i].tx.ringBuf[j].u16Items;
        }
    }
}

/* rx data copy to ring buf */
static int8_t commRxRingWrite(commDataTypedef* pCommEntity, uint8_t* data, uint32_t size)
{
    uint8_t offset = 0;

    if (pCommEntity == NULL || data == NULL || size == 0)
    {
        COMMINTERFACE_DEBUG("%s para Error\n", __FUNCTION__);
        return -1;
    }

    /* if the size of data that get from dma buf is greater than one msg size, must write twice */
    if (size > pCommEntity->rx.ringItemSize)
    {
        COMMINTERFACE_DEBUG("msg rx %x size too long %d->%d\n", pCommEntity->rx.msgId, size, pCommEntity->rx.ringItemSize);
        if (wl_ringbuf_write(&pCommEntity->rx.ringBuf, data, pCommEntity->rx.ringItemSize) < 0)
        {
            COMMINTERFACE_DEBUG("msg rx %x write rb error\n", pCommEntity->rx.msgId);
            return -1;
        }

        if (pCommEntity->rx.msgId != 0)
        {
            if (commQueueSend(pCommEntity->rx.msgId>>8, pCommEntity->rx.msgId) != pdTRUE)
            {
                COMMINTERFACE_DEBUG("msg rx %x queue push error\n", pCommEntity->rx.msgId);
            }
        }

        offset = pCommEntity->rx.ringItemSize;
    }

    if (wl_ringbuf_write(&pCommEntity->rx.ringBuf, data+offset, size-offset) < 0)
    {
        COMMINTERFACE_DEBUG("msg rx %x write rb error\n", pCommEntity->rx.msgId);
        return -1;
    }

    if (pCommEntity->rx.msgId != 0)
    {
        if (commQueueSend(pCommEntity->rx.msgId>>8, pCommEntity->rx.msgId) != pdTRUE)
        {
            COMMINTERFACE_DEBUG("msg rx %x queue push error\n", pCommEntity->rx.msgId);
        }
    }

    return 0;
}

/* rx data read from ring buf */
static int8_t commRxRingRead(commDataTypedef* pCommEntity, uint8_t* data, uint32_t*size)
{
    if (pCommEntity == NULL || data == NULL || size == NULL)
    {
        COMMINTERFACE_DEBUG("%s para Error\n", __FUNCTION__);
        return -1;
    }

    if (wl_ringbuf_read(&pCommEntity->rx.ringBuf, data, size) >= 0)
    {
        return 0;
    }

    return -1;
}

/* tx data copy to ring buf */
static int8_t commTxRingWrite(commDataTypedef* pCommEntity, uint8_t* data, uint32_t size, uint8_t firstRing)
{
    int32_t ret = 0;

    if (pCommEntity == NULL || data == NULL || size == 0)
    {
        COMMINTERFACE_DEBUG("commTxRingWrite para Error\n");
        return -1;
    }

    if (size > pCommEntity->tx.ringItemSize)
    {
        COMMINTERFACE_DEBUG("msg tx %x size too long %d->%d\n", pCommEntity->tx.msgId, size, pCommEntity->tx.ringItemSize);
        return -1;
    }

    /* avoid tx.busy dead lock */ 
    if (pCommEntity->tx.busy == 1 && pCommEntity->tx.busyStamp > getSystemTimestamp()+100)
    {
        pCommEntity->tx.busy = 0;
        COMMINTERFACE_DEBUG("msg tx %x busy timeout %d\n", pCommEntity->tx.msgId, (uint32_t)pCommEntity->tx.busyStamp);
    }

    for (uint8_t i=0; i<pCommEntity->tx.ringDiv; i++)
    {
        ret = wl_ringbuf_write(&pCommEntity->tx.ringBuf[(i+firstRing)%pCommEntity->tx.ringDiv], data, size);
        if (ret >= 0 || ret == ERR_RINGBUF_BUF_FULL)            /* avoid all ringbuf full, dead lock */
        {
            if (pCommEntity->tx.msgId != 0 && pCommEntity->tx.busy == 0 && osKernelRunning() == 1)
            {
                if (commQueueSend(pCommEntity->tx.msgId>>8, pCommEntity->tx.msgId) != pdTRUE)
                {
                    //COMMINTERFACE_DEBUG("msg tx %x queue push error\n", pCommEntity->tx.msgId);
                }
            }

            if (ret >=0 )
            {
                return 0;
            }
        }
    }

    /* last ringbuf group */
    if (ret == ERR_RINGBUF_BUF_FULL && (pCommEntity == &commEntity[DEBUG_COMM_TYPE] || pCommEntity == &commEntity[ACU_COMM_TYPE]))
    {
        /* do not print, avoid ringbuf dead-lock */
    }
    else
    {
        // COMMINTERFACE_DEBUG("msg tx %x loss data E%x\n", pCommEntity->tx.msgId, ret);
    }

    return -1;
}

/* tx data read from ring buf */
static int8_t commTxRingRead(commDataTypedef* pCommEntity, uint8_t* data, uint32_t* size)
{
    if (pCommEntity == NULL || data == NULL || size == NULL)
    {
        COMMINTERFACE_DEBUG("commTxRingRead para Error\n");
        return -1;
    }

    for (uint8_t i=0; i<pCommEntity->tx.ringDiv; i++)
    {
        if (wl_ringbuf_read(&pCommEntity->tx.ringBuf[i], data, size) >= 0)
        {
            return 0;
        }
    }

    return -1;
}

COMM_TYPE_ENUM commGetEntirtyTypeByDevHandler(void* dev)
{
    for (uint8_t i=0; i< sizeof(commEntity)/sizeof(commEntity[0]); i++)
    {
        if (commEntity[i].comm == dev)
        {
            return i;
        }
    }

    return COMM_MAX;
}

int32_t commRxRingGetFreeItem(COMM_TYPE_ENUM type)
{
    if (type >= COMM_MAX)
    {
        return -1;
    }

    return wl_ringbuf_freeSize(&commEntity[type].rx.ringBuf);
}

int32_t commTxRingGetFreeItem(COMM_TYPE_ENUM type)
{
    uint8_t sum = 0;

    if (type >= COMM_MAX)
    {
        return -1;
    }

    for (uint8_t i=0; i<commEntity[type].tx.ringDiv; i++)
    {
        sum += wl_ringbuf_freeSize(&commEntity[type].tx.ringBuf[i]);
    }

    return sum;
}

/* debug ring buf log */
void commMonitorRingAndLoss(void)
{
    char logBuf[BUF_LOG_ITEM_SIZE];
    uint8_t size;
    uint8_t len = 0;

    for (uint8_t i=0; i< sizeof(commEntity)/sizeof(commEntity[0]); i++)
    {
        /* ring */
        len = 0;
        memset(logBuf, 0, BUF_LOG_ITEM_SIZE);
        size = snprintf(logBuf, BUF_LOG_ITEM_SIZE, "COM %d R[%d %d %d] T", i, commEntity[i].rx.ringBuf.u16Items, commEntity[i].rx.ringBuf.leftItem, commEntity[i].rx.ringBuf.minLeftItem);
        len += size;
        for (uint8_t j=0; j<commEntity[i].tx.ringDiv; j++)
        {
            size = snprintf(logBuf+len, BUF_LOG_ITEM_SIZE-len, "[%d %d %d] ", commEntity[i].tx.ringBuf[j].u16Items, commEntity[i].tx.ringBuf[j].leftItem, commEntity[i].tx.ringBuf[j].minLeftItem);
            len += size;
        }
        size = snprintf(logBuf+len, BUF_LOG_ITEM_SIZE-len, "Loss[%ld %ld] ErrCnt%ld\n", commEntity[i].tx.loss, commEntity[i].rx.loss, commEntity[i].err_cnt);

        COMMINTERFACE_INFO("%s", logBuf);
    }
}

/* debug uart log */
void commMonitorError(void)
{
    for (uint8_t i=0; i< sizeof(commEntity)/sizeof(commEntity[0]); i++)
    {
        if (commEntity[i].last_err_code != 0)
        {
            COMMINTERFACE_INFO("COM%d err %x\n", i, commEntity[i].last_err_code);
            commEntity[i].last_err_code = 0;
        }
    }
}

/* push data to rx ring */
int32_t commRxRingPush(COMM_TYPE_ENUM type, uint8_t* data, uint32_t size)
{
    if (type >= COMM_MAX)
    {
        return -1;
    }

    return commRxRingWrite(&commEntity[type], data, size);
}

/* unpack data by  ninebot protocol */
static int32_t unpackData(COMM_TYPE_ENUM type, uint8_t* ps8Data, int32_t s32Len, void (*comProcessFunc)(COMM_TYPE_ENUM, uint8_t*, uint32_t))
{
    int32_t s32Pos = 0;
    int32_t i = 0;
	uint8_t len = 0;
    uint16_t u16Crc;
    uint16_t u16CrcRcv;

    while (1)
    {
        for (i=s32Pos; i<s32Len-1; i++)
        {
            if (DATA_HEAD0 == ps8Data[i] && DATA_HEAD1 == ps8Data[i + 1])
            {
                break;
            }
        }

        if (i != s32Pos)
        {
            COMMINTERFACE_DEBUG("type %d %d %d %d\n", type, i, s32Pos, s32Len);
        }

        if  (s32Len < i+3)
        {
            return i;
        }
  
        len = ps8Data[i+2];

        if (s32Len < i+9+len)
        {
            return i;
        }
        /* check src id ==comm match */


        // check crc
        u16Crc = GetCrc16((uint8_t*)&ps8Data[i + 2], len + 5);
        u16CrcRcv = (ps8Data[i+8+len] << 8) | ps8Data[i + 7 + len];
        if (u16Crc != u16CrcRcv)
        {
            COMMINTERFACE_DEBUG("type:%d %x->%x, i %d/%d index %x, len %d, crc error 0x%x, 0x%x\r\n", type, ps8Data[i+3], ps8Data[i+4], i, s32Len, ps8Data[i+6], ps8Data[i+2], u16Crc, u16CrcRcv);
            s32Pos = i + 2;
        }
        else
        {
            comProcessFunc(type, &ps8Data[i], len+9);
            s32Pos = i + len + 9;
        }
    }
}

/* pop data from rx ring, and parse data by protocol of comm */
int32_t commRxRingPopAndProcess(COMM_TYPE_ENUM type, void (*comProcessFunc)(COMM_TYPE_ENUM, uint8_t*, uint32_t))
{
    uint32_t size;
    uint16_t offset;

    if (type >= COMM_MAX)
    {
        return -1;
    }

    /* get data from ring buff */
    if (commRxRingRead(&commEntity[type], &commEntity[type].rx.unpack.buf[commEntity[type].rx.unpack.left], &size) < 0)
    {
        return -1;
    }

    if (type == DEBUG_COMM_TYPE)         /* not ninebox procotol */
    {
        if (size <= 5)
        {
            return -1;
        }

        comProcessFunc(type, commEntity[type].rx.unpack.buf, size);
    }
    else
    {
        /* unpack data */
        commEntity[type].rx.unpack.left += size;
        offset = unpackData(type, commEntity[type].rx.unpack.buf, commEntity[type].rx.unpack.left, comProcessFunc);

        /* if left size > ring item size, drop some */
        if (commEntity[type].rx.unpack.left - offset > commEntity[type].rx.ringItemSize)
        {
            offset = commEntity[type].rx.unpack.left - commEntity[type].rx.ringItemSize;
            COMMINTERFACE_DEBUG("COMM Buffer full msg[%d] %d+%d\n", commEntity[type].rx.msgId, commEntity[type].rx.unpack.left, size);
        }

        /* remove left data to buf head */
        commEntity[type].rx.unpack.left -= offset;


        if (commEntity[type].rx.unpack.left > 0)
        {
            memcpy(commEntity[type].rx.unpack.buf, &commEntity[type].rx.unpack.buf[offset], commEntity[type].rx.unpack.left);
        }
    }

    return 0;
}

/* pack data, ninebot comm protocol */
static void __packData(uint8_t* ps8DstBuf, uint8_t *pu8SrcData, uint8_t u8SrcDataSize, uint8_t u8Index, uint8_t u8Cmd, uint8_t u8SrcId, uint8_t u8DstId)
{
    uint16_t  u16Crc;

    ps8DstBuf[0] = 0x5A;
    ps8DstBuf[1] = 0xA5;
    ps8DstBuf[2] = u8SrcDataSize;
    ps8DstBuf[3] = u8SrcId;
    ps8DstBuf[4] = u8DstId;
    ps8DstBuf[5] = u8Cmd;
    ps8DstBuf[6] = u8Index;

    if ((NULL != pu8SrcData) && (0 != u8SrcDataSize))
    {
        memcpy(&ps8DstBuf[7], pu8SrcData, u8SrcDataSize);
    }

    u16Crc = GetCrc16((uint8_t*)&ps8DstBuf[2], u8SrcDataSize + 5);

    ps8DstBuf[u8SrcDataSize + 7] = u16Crc & 0xff;
    ps8DstBuf[u8SrcDataSize + 8] = (u16Crc >> 8) & 0xff;
}

/* push data to tx ring */
int32_t commTxRingPush(COMM_TYPE_ENUM type, uint8_t *pData, uint32_t size, uint8_t firstRing)
{
    int32_t ret;

    if (type >= COMM_MAX)
    {
        return -1;
    }

    ret = commTxRingWrite(&commEntity[type], pData, size, firstRing);
    if (ret < 0)
    {
        commEntity[type].tx.loss++;
    }

    return ret;
}

/* push ninebot protocol data to tx ring */
int32_t commTxRingPushNinebotData(COMM_TYPE_ENUM type, uint8_t *pu8Data, uint8_t u8DataSize, uint8_t u8Index, uint8_t u8Cmd, uint8_t u8SrcId, uint8_t u8DstId, uint8_t firstRing)
{
    uint8_t ps8Buf[MAX_ITEM_SIZE] = {0};

    if (u8DataSize+9 > MAX_ITEM_SIZE)
    {
        return -1;
    }

    __packData(ps8Buf, pu8Data, u8DataSize, u8Index, u8Cmd, u8SrcId, u8DstId);

    return commTxRingPush(type, ps8Buf, u8DataSize+9, firstRing);
}

/* push data to uart DMA */
int32_t commTxDirectNinebotData(COMM_TYPE_ENUM type, uint8_t *pu8Data, uint8_t u8DataSize, uint8_t u8Index, uint8_t u8Cmd, uint8_t u8SrcId, uint8_t u8DstId)
{
    uint8_t ps8Buf[MAX_ITEM_SIZE] = {0};

    if (u8DataSize+9 > MAX_ITEM_SIZE)
    {
        return -1;
    }

    __packData(ps8Buf, pu8Data, u8DataSize, u8Index, u8Cmd, u8SrcId, u8DstId);

    return HAL_UART_Transmit_DMA(commEntity[ACU_COMM_TYPE].comm, ps8Buf, u8DataSize+9);
}

/* pop data from SPI comm ringbuf */
int32_t commTxRingPop_SPI(COMM_TYPE_ENUM type, uint8_t* data, uint32_t len)
{
    uint32_t size = 0;

    if (type >= COMM_MAX)
    {
        return -1;
    }

    if (commTxRingRead(&commEntity[type], commEntity[type].tx.buf, &size) < 0)
    {
        return -1;
    }

    if(size > len)
    {
        size = len;
    }
    memcpy(data, commEntity[type].tx.buf, size);

    return size;
}

/* pop Data from uart tx ring, and start dma transmit */
int32_t commTxRingPop_UART(COMM_TYPE_ENUM type)
{
    uint32_t size;

    if (type >= COMM_UART_MAX)
    {
        return -1;
    }

    if (commEntity[type].tx.busy == 1)
	{
        return -1;
    }

    if (commTxRingRead(&commEntity[type], commEntity[type].tx.buf, &size) < 0)
    {
        commEntity[type].tx.busy = 0;
        return -1;
    }

    commEntity[type].tx.busy = 1;
    if (uart_tx_startDMA(commEntity[type].comm, commEntity[type].tx.buf, size) != HAL_OK)
    {
        commEntity[type].tx.busy = 0;
        COMMINTERFACE_DEBUG("COMM dma transt fail type[%d] size %d cmd %x index %x\n", type, size, commEntity[type].tx.buf[5], commEntity[type].tx.buf[6]);
    }
    else
    {
        commEntity[type].tx.busyStamp = getSystemTimestamp();
    }

    return 0;
}
#endif